//
//  WZAttrbuteLabel.m
//  WZEfengAndEtong
//
//  Created by wanzhao on 16/3/24.
//  Copyright © 2016年 wanzhao. All rights reserved.
//

#import "WZAttrbuteLabel.h"
#import "WZAttributedAction.h"
#import <CoreText/CoreText.h>

@implementation WZAttrbuteLabel

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {
        UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(didLongPress:)];
        longPress.minimumPressDuration = 0.4f;
        [self addGestureRecognizer:longPress];

        [self addHotspotHandler];
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(didLongPress:)];
        longPress.minimumPressDuration = 0.4f;
        [self addGestureRecognizer:longPress];

        [self addHotspotHandler];
    }
    return self;
}

-(void)addHotspotHandler
{
    __weak WZAttrbuteLabel* weakSelf = self;
    [self setOnTap:^(CGPoint pt) {
        // Locate the text attributes at the touched position
        NSDictionary* attributes = [weakSelf textAttributesAtPoint:pt];
        // If the touched attributes contains our custom action style, execute the action block
        WZAttributedAction* actionStyle = attributes[@"action"];
        if (actionStyle) {
            actionStyle.action();
        } else {
            if (weakSelf.labeClickAction) {
                weakSelf.labeClickAction();
            }
            
        }
    }];
}


-(void)setOnTap:(void (^)(CGPoint))onTap
{
    _onTap = onTap;
    UITapGestureRecognizer* tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
    [self addGestureRecognizer:tapGesture];
    self.userInteractionEnabled = YES;
}

-(void)tapped:(UITapGestureRecognizer*)gesture
{
    if (gesture.state == UIGestureRecognizerStateRecognized) {
        CGPoint pt = [gesture locationInView:self];
        if (self.onTap) {
            self.onTap(pt);
        }
    }
}


-(NSDictionary*)textAttributesAtPoint:(CGPoint)pt
{
    // Locate the attributes of the text within the label at the specified point
    NSDictionary* dictionary = nil;
    
    // First, create a CoreText framesetter
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)self.attributedText);
    
    CGMutablePathRef framePath = CGPathCreateMutable();
    CGPathAddRect(framePath, NULL, CGRectMake(0, 0, self.width, self.height));
    // Get the frame that will do the rendering.
    CFRange currentRange = CFRangeMake(0, 0);
    CTFrameRef frameRef = CTFramesetterCreateFrame(framesetter, currentRange, framePath, NULL);
    CGPathRelease(framePath);
    
    // Get each of the typeset lines
    NSArray *lines = (__bridge id)CTFrameGetLines(frameRef);
    
    CFIndex linesCount = [lines count];
    CGPoint *lineOrigins = (CGPoint *) malloc(sizeof(CGPoint) * linesCount);
    CTFrameGetLineOrigins(frameRef, CFRangeMake(0, 0), lineOrigins);
    
    CTLineRef line = NULL;
    CGPoint lineOrigin = CGPointZero;
    
    // Correct each of the typeset lines (which have origin (0,0)) to the correct orientation (typesetting offsets from the bottom of the frame)
    
    // Scan through each line to find the line containing the touch point y position
    for(CFIndex i = 0; i < linesCount; ++i) {
        line = (__bridge CTLineRef)[lines objectAtIndex:i];
        lineOrigin = lineOrigins[linesCount - i - 1];
        
        CGFloat descent, ascent;
        CGFloat width = CTLineGetTypographicBounds(line, &ascent, &descent, nil);
        if (pt.y >= (CGFloat)floor(lineOrigin.y - descent)) {
            
        
        if(pt.y <= ((CGFloat)ceil(lineOrigin.y + ascent))) {
            
            // Cater for text alignment set in the label itself (not in the attributed string)
            // Offset the touch position by the actual typeset line origin. pt is now the correct touch position with the line bounds
            
            // Find the text index within this line for the touch position
            if (pt.x >= lineOrigin.x && pt.x <= lineOrigin.x + width) {
                CFIndex i = CTLineGetStringIndexForPosition(line, CGPointMake(pt.x - lineOrigin.x, pt.y - lineOrigin.y));
                
                // Iterate through each of the glyph runs to find the run containing the character index
                NSArray* glyphRuns = (__bridge id)CTLineGetGlyphRuns(line);
                CFIndex runCount = [glyphRuns count];
                for (CFIndex run = 0; run < runCount; run++) {
                    CTRunRef glyphRun = (__bridge CTRunRef)[glyphRuns objectAtIndex:run];
                    CFRange range = CTRunGetStringRange(glyphRun);
                    
                    if (i >= range.location && i <= range.location + range.length) {
                        dictionary = (__bridge NSDictionary*)CTRunGetAttributes(glyphRun);
                       
                        break;
                    }
                }
                
            }
            
            if (dictionary) {
                break;
            }
        }
    }
    }
    
    free(lineOrigins);
    CFRelease(frameRef);
    CFRelease(framesetter);
    
    
    return dictionary;
}


- (void)didLongPress:(UILongPressGestureRecognizer *)longPress
{
    if(longPress.state != UIGestureRecognizerStateBegan || ![self becomeFirstResponder])
        return;
    UIMenuController *menu = [UIMenuController sharedMenuController];
    
    
    
    CGRect targetRect = [self convertRect:CGRectMake(0, 0, self.width, self.height)
                                 fromView:self];
    [menu setTargetRect:CGRectInset(targetRect, 0.0f, 4.0f) inView:self];
    [menu setMenuVisible:YES animated:YES];
    //    [self handleLongText];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleMenuWillShowNotification:)
                                                 name:UIMenuControllerWillShowMenuNotification
                                               object:nil];
    
}

#pragma mark - Copying
- (BOOL)canBecomeFirstResponder
{
    return YES;
}

- (BOOL)becomeFirstResponder
{
    return [super becomeFirstResponder];
}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
    [super canPerformAction:action withSender:sender];
    if(action == @selector(copy:))
        return YES;
    //    if (action==@selector(delete:)) {
    //        return YES;
    //    }
    return NO;
}


- (void)copy:(id)sender
{
    [[UIPasteboard generalPasteboard] setString:self.pasteStr];
    [self resignFirstResponder];
}



#pragma mark - Notification
- (void)handleMenuWillHideNotification:(NSNotification *)notification
{
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIMenuControllerWillHideMenuNotification
                                                  object:nil];
}

- (void)handleMenuWillShowNotification:(NSNotification *)notification
{
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIMenuControllerWillShowMenuNotification
                                                  object:nil];
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleMenuWillHideNotification:)
                                                 name:UIMenuControllerWillHideMenuNotification
                                               object:nil];
    
}


@end
